package org.playground.booking.dao.impl;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.playground.booking.dao.IDao;
import org.playground.booking.entity.PlaygrounEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import javax.persistence.Id;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

/**
 * Created by root on 17-10-28.
 */
@Repository
public class AbstractDaoImpl<T extends PlaygrounEntity,K> implements IDao<T,K> {

    @Autowired
    private SessionFactory sessionFactory;

    protected Session getCurrentSession(){
        return this.sessionFactory.getCurrentSession();
    }

    protected Class<T> getEntityType(){
        Type genericSuperClass = this.getClass().getGenericSuperclass();
        if(genericSuperClass instanceof ParameterizedType){
            ParameterizedType pt = (ParameterizedType)genericSuperClass;
            Type[] paramTypes = pt.getActualTypeArguments();
            return paramTypes.length==0?(Class<T>)genericSuperClass:(Class<T>)paramTypes[0];
        }else{
            return (Class<T>)genericSuperClass;
        }
    }


    public List<T> readAll() {
        String hql = "from "+this.getEntityType().getName();
        Query query = this.getCurrentSession().createQuery(hql);
        return query.list();
    }

    public List<T> readByCreterias(String hql, Map<String, Object> params) {
        return null;
    }

    public T readById(K id) {
        String idName = getIdAttributeName();

        String hql = "from "+this.getEntityType().getName()+ " obj" +
                " where "+idName+" =:id";
        Query query = this.getCurrentSession().createQuery(hql);
        query.setParameter("id",id);

        List<T> found = query.list();

        return found.size()==0?null:found.get(0);
    }

    private String getIdAttributeName(){
        Field[] fields = this.getEntityType().getDeclaredFields();
        for(Field field : fields){
            Id idAnno = field.getAnnotation(Id.class);
            if(idAnno!=null){
                return field.getName();
            }
        }
        return "id";
    }

    public void update(T toUpdate) {
        this.getCurrentSession().saveOrUpdate(toUpdate);
    }

    public void delete(T toDelete) {
        this.getCurrentSession().delete(toDelete);
    }

    public void save(T toSave) {
        this.getCurrentSession().saveOrUpdate(toSave);
    }
}
